---
sidebar_position: 9
---

# framebuffer

Framebuffer command takes a high-quality, uncompressed screenshot of the device screen.

Framebuffer command is actually a wrapper for `screencap` executable, only uses binary output format instead of PNG. `screencap` changed its binary output format in Android 9, so it's difficult for a client to directly parse it without knowing the Android version first. Because `framebuffer` command is implemented in ADB daemon and shipped with `screencap` on the device, it always knows the correct format.

Because the binary format contains raw RGB values, it's easier to parse than PNG. However, it requires much more bandwidth to transfer. If the client can decode PNG, it's recommended to use `screencap` command instead.

```ts
interface AdbFrameBuffer {
  bpp: number;
  colorSpace?: number;
  size: number;
  width: number;
  height: number;
  red_offset: number;
  red_length: number;
  blue_offset: number;
  blue_length: number;
  green_offset: number;
  green_length: number;
  alpha_offset: number;
  alpha_length: number;
  data: Uint8Array;
}

declare class Adb {
  framebuffer(): Promise<AdbFrameBuffer>;
}
```

## Color Space

On Android 9 and above, `colorSpace` field is present in the output. The values are:

* `0`: Unknown
* `1`: sRGB
* `2`: Display P3

## Color Format

The four `color_offset` and `color_length` fields are numbers in bits. Some common color formats are presented by

| field          | RGBA_8888 | RGBX_8888 | RGB_888 | RGB_565  | BGRA_8888 |
| -------------- | --------- | --------- | ------- | ------- | --------- |
| `bpp`          | 32        | 32        | 24      | 16      | 32        |
| `red_offset`   | 0         | 0         | 0       | 11      | 16        |
| `red_length`   | 8         | 8         | 8       | 5       | 8         |
| `green_offset` | 8         | 8         | 8       | 5       | 8         |
| `green_length` | 8         | 8         | 8       | 6       | 8         |
| `blue_offset`  | 16        | 16        | 16      | 0       | 0         |
| `blue_length`  | 8         | 8         | 8       | 5       | 8         |
| `alpha_offset` | 24        | 24        | 0       | 0       | 24        |
| `alpha_length` | 8         | 0         | 0       | 0       | 8         |

:::note

* I have only seen RGBA_8888 format
* RGB_565 is actually BGR_565, but [Android source code](https://android.googlesource.com/platform/packages/modules/adb/+/bafac63cab3d32f7bf0e4cb0d8ff00e7e59a4e22/daemon/framebuffer_service.cpp#139) calls it RGB_565

:::

## Errors

```ts
declare abstract class AdbFrameBufferError extends Error {}

declare class AdbFrameBufferUnsupportedVersionError extends AdbFrameBufferError {}

declare class AdbFrameBufferForbiddenError extends AdbFrameBufferError {}
```

Framebuffer command has multiple versions, currently Tango supports version 1 and 2. If the device returns an unsupported version, an `AdbFrameBufferUnsupportedVersionError` will be thrown.

Apps can disable screenshot by setting `FLAG_SECURE` flag on their windows. If the device is in this state, an `AdbFrameBufferForbiddenError` will be thrown.

## Examples

### Take a screenshot

```ts transpile
const screenshot = await adb.framebuffer();
```

:::info[Equivalent ADB Command]

```sh
adb exec-out screencap -p > screenshot.png
```

:::

### Draw the screenshot to a canvas

Assume the screenshot has RGBA8888 color format:

```ts transpile
const canvas = document.createElement("canvas");

canvas.width = screenshot.width;
canvas.height = screenshot.height;

const context = canvas.getContext("2d")!;
const imageData = new ImageData(
  new Uint8ClampedArray(screenshot.data),
  screenshot.width,
  screenshot.height,
);
context.putImageData(imageData, 0, 0);
```

### Save the canvas into a PNG file

```ts transpile
const url = canvas.toDataURL();
const a = document.createElement("a");
a.href = url;
a.download = `screenshot.png`;
a.click();
```
